<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>calculator</title>
        <!-- <script src="vue.min.js"></script> -->
        <script src="https://unpkg.com/vue/dist/vue.min.js"></script>
        <!-- <script src="js.cookie.js"></script> -->
        <script type="text/javascript">
/*!
 * JavaScript Cookie v2.1.4
 * https://github.com/js-cookie/js-cookie
 *
 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
 * Released under the MIT license
 */
;(function (factory) {
    var registeredInModuleLoader = false;
    if (typeof define === 'function' && define.amd) {
        define(factory);
        registeredInModuleLoader = true;
    }
    if (typeof exports === 'object') {
        module.exports = factory();
        registeredInModuleLoader = true;
    }
    if (!registeredInModuleLoader) {
        var OldCookies = window.Cookies;
        var api = window.Cookies = factory();
        api.noConflict = function () {
            window.Cookies = OldCookies;
            return api;
        };
    }
}(function () {
    function extend () {
        var i = 0;
        var result = {};
        for (; i < arguments.length; i++) {
            var attributes = arguments[ i ];
            for (var key in attributes) {
                result[key] = attributes[key];
            }
        }
        return result;
    }

    function init (converter) {
        function api (key, value, attributes) {
            var result;
            if (typeof document === 'undefined') {
                return;
            }

            // Write

            if (arguments.length > 1) {
                attributes = extend({
                    path: '/'
                }, api.defaults, attributes);

                if (typeof attributes.expires === 'number') {
                    var expires = new Date();
                    expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
                    attributes.expires = expires;
                }

                // We're using "expires" because "max-age" is not supported by IE
                attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';

                try {
                    result = JSON.stringify(value);
                    if (/^[\{\[]/.test(result)) {
                        value = result;
                    }
                } catch (e) {}

                if (!converter.write) {
                    value = encodeURIComponent(String(value))
                        .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
                } else {
                    value = converter.write(value, key);
                }

                key = encodeURIComponent(String(key));
                key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
                key = key.replace(/[\(\)]/g, escape);

                var stringifiedAttributes = '';

                for (var attributeName in attributes) {
                    if (!attributes[attributeName]) {
                        continue;
                    }
                    stringifiedAttributes += '; ' + attributeName;
                    if (attributes[attributeName] === true) {
                        continue;
                    }
                    stringifiedAttributes += '=' + attributes[attributeName];
                }
                return (document.cookie = key + '=' + value + stringifiedAttributes);
            }

            // Read

            if (!key) {
                result = {};
            }

            // To prevent the for loop in the first place assign an empty array
            // in case there are no cookies at all. Also prevents odd result when
            // calling "get()"
            var cookies = document.cookie ? document.cookie.split('; ') : [];
            var rdecode = /(%[0-9A-Z]{2})+/g;
            var i = 0;

            for (; i < cookies.length; i++) {
                var parts = cookies[i].split('=');
                var cookie = parts.slice(1).join('=');

                if (cookie.charAt(0) === '"') {
                    cookie = cookie.slice(1, -1);
                }

                try {
                    var name = parts[0].replace(rdecode, decodeURIComponent);
                    cookie = converter.read ?
                        converter.read(cookie, name) : converter(cookie, name) ||
                        cookie.replace(rdecode, decodeURIComponent);

                    if (this.json) {
                        try {
                            cookie = JSON.parse(cookie);
                        } catch (e) {}
                    }

                    if (key === name) {
                        result = cookie;
                        break;
                    }

                    if (!key) {
                        result[name] = cookie;
                    }
                } catch (e) {}
            }

            return result;
        }

        api.set = api;
        api.get = function (key) {
            return api.call(api, key);
        };
        api.getJSON = function () {
            return api.apply({
                json: true
            }, [].slice.call(arguments));
        };
        api.defaults = {};

        api.remove = function (key, attributes) {
            api(key, '', extend(attributes, {
                expires: -1
            }));
        };

        api.withConverter = init;

        return api;
    }

    return init(function () {});
})); 

        </script> 
        <style type="text/css">
        .app {
            width: 20em;
            margin: 0 auto;
            font-family: monospace;
            font-size: 2em;
        }
        .app-m {
            width: 100%;
            font-size: 8em;
        }
        button {
            font-family: monospace;
            font-size: 1em;
        }
        input {
            font-family: monospace;
            font-size: 1em;
        }
        .res {
            margin: 0;
            border: 0;
            padding: 0;
            font-size: 1em;
            width: 100%;
            text-align: left;
        }
        .res-2 {
            background-color: #2973b7;
        }
        .res-3 {
            background-color: #42b983;
        }
        table.layout {
            border-collapse: collapse;
            margin: 0;
            border: 0;
            padding: 0;
        }
        table.layout tr, table.layout td {
            margin: 0;
            border: 0;
            padding: 0;
        }
        table.layout .button {
            margin: 0;
            border: 0;
            width: 100%;
            font-size: 1.0em;
            text-align: center;
        }
        table.layout .button:hover {
            background-color: #ff9800;
        }
        .on {
            background-color: red;
        }
        .input {
            margin: 0;
            border: 0;
            padding: 0;
            width: 100%;
        }
        .input-text {
            width: 100%;
            font-family: monospace;
            font-size: 1em;
            border: 0;
            background-color: #DEDFF2;
        }
        .history {
            width: 100%;
        }
        .e-input {
            width: 100%;
        }
        .e-input:hover {
            background-color: #ff9800;
        }
        .e-res {
            width: 5em;
            text-align: right;
        }

        </style>
    </head>
    <body>
        <div id="app" :class="['app', {'app-m': is_mobile}]">
            <input type="text" class="res" v-model="res" disabled="true" />
            <input v-if="hex" type="text" class="res res-2" :value=" parseInt(res).toString(16).toUpperCase() "/>
            <input v-if="bin" type="text" class="res res-3" :value=" parseInt(res).toString(2) "/>
            <table class="layout">
                <tr>
                    <td><button class="button" @click="add('1')">1</button></td>
                    <td><button class="button" @click="add('2')">2</button></td>
                    <td><button class="button" @click="add('3')">3</button></td>
                    <td><button class="button" @click="add('4')">4</button></td>
                    <td><button class="button" @click="add('5')">5</button></td>
                    <td><button class="button" @click="add('6')">6</button></td>
                    <td><button class="button" @click="add('7')">7</button></td>
                    <td><button class="button" @click="add('8')">8</button></td>
                    <td><button class="button" @click="add('9')">9</button></td>
                    <td><button class="button" @click="add('0')">0</button></td>
                    <td><button class="button" @click="add('.')">.</button></td>
                    <td><button :class="['button', {on: hex}]" @click="hex = (hex == true) ? false : true">H</button></td>
                </tr>
                <tr>
                    <td><button class="button" @click="add('+')">+</button></td>
                    <td><button class="button" @click="add('-')">-</button></td>
                    <td><button class="button" @click="add('*')">*</button></td>
                    <td><button class="button" @click="add('/')">/</button></td>
                    <td><button class="button" @click="add('(')">(</button></td>
                    <td><button class="button" @click="add(')')">)</button></td>
                    <td colspan="2"><button class="button" @click="calc">=</button></td>
                    <td colspan="2"><button class="button" @click="bs">&lt;</button></td>
                    <td><button class="button" @click="clear">C</button></td>
                    <td><button :class="['button', {on: bin}]" @click="bin = (bin == true) ? false : true">B</button></td>
                </tr>
            </table>
            <input type="text" class="input-text" v-model="input" @keyup.enter="calc" id="input">

            <table class="layout">
                <tr v-for="e in reversed_history">
                    <td class="e-input" @click="cp_history(e)"> {{ e.input }} </td>
                    <td class="e-eq"> = </td>
                    <td class="e-res"> {{ e.res }} </td>
                    <td> <button class="button" @click="rm(e.id)">X</button></td>
                </tr>
            </table>
        </div>
    </body>
    <script type="text/javascript">
        var data = {
            input: '',
            history: [],
            max_history: 20,
            is_mobile: false,
            hex: false,
            bin: false,
            new_offset: 0,
        };
        var app = new Vue({
            el: '#app',
            data: data,
            computed: {
                reversed_history: function() {
                    return this.history.slice().reverse();
                },
                res: function() {
                    var input = this.input;
                    var res;
                    try {
                        // todo: check input validation before eval: re replace '0x' and check there is no characters other then numbers and +-/*()
                        res = eval(input).toFixed(3);
                    }
                    catch(err) {
                        return '';
                    }
                    var int_res = Math.floor(res);
                    if (int_res == res) {
                        res = int_res;
                    }
                    return res;
                }
            },
            methods: {
                calc: function() {
                    if (this.res == '') {
                        return;
                    }
                    if (this.history.filter(function(e){return e.input == app.input;}).length != 0) {
                        return;
                    }
                    this.history.push({
                        input: this.input,
                        res: this.res,
                        id: this.uid()
                    });
                    this.update_cookie();
                },
                rm: function(id) {
                    var len = this.history.length;
                    for (var i=0;i<len;i++) {
                        if (this.history[i].id == id) {
                            this.history.splice(i, 1);
                            break;
                        }
                    }
                    this.update_cookie();
                },
                cp_history: function(e) {
                    this.input = e.input;
                },
                add: function(s) {
                    var v = this.input;
                    var text_box = document.getElementById('input');
                    var start_offset = text_box.selectionStart;
                    var end_offset = text_box.selectionEnd;
                    var new_offset = start_offset + s.length;
                    // if(s == '(') {
                    //     s += ')';
                    // }
                    this.input = v.slice(0, start_offset) + s + v.slice(end_offset);
                    // this.update_cursor(new_offset);
                    // window.setTimeout(function(){
                    //     text_box.selectionStart = new_offset;
                    //     text_box.selectionEnd = new_offset;
                    // }, 0.5);
                },
                bs: function() {
                    var v = this.input;
                    var text_box = document.getElementById('input');
                    var start_offset = text_box.selectionStart;
                    var end_offset = text_box.selectionEnd;
                    var new_offset = start_offset-1;
                    this.input = v.slice(0, start_offset-1) + v.slice(end_offset);
                    // this.update_cursor(new_offset);
                },
                clear: function() {
                    this.input = '';
                },
                update_cookie: function() {
                    var start_offset = this.history.length - this.max_history;
                    start_offset = start_offset < 0 ? 0 : start_offset;
                    Cookies.set('history', this.history.slice(start_offset, start_offset + this.max_history), { expires: 365 });
                },
                uid: function() {
                    return Math.floor((1 + Math.random()) * 0x10000);
                },
                update_cursor: function(new_offset) {
                    this.new_offset = new_offset;
                    window.setTimeout(function(){
                        var text_box = document.getElementById('input');
                        console.log('set new_offset to ' + app.new_offset + ', get: ' + text_box.selectionStart + ' / ' + text_box.selectionEnd);
                        text_box.selectionStart = app.new_offset;
                        text_box.selectionEnd = app.new_offset;
                        console.log('set new_offset to ' + app.new_offset + ', get: ' + text_box.selectionStart + ' / ' + text_box.selectionEnd);
                    }, 0.5);
                }
            }
        });
        function is_mobile() {
            var check = false;
            (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
            return check;
        };
        function init() {
            var c = Cookies.getJSON('history');
            if (c == null || c.length == 0) {
                app.input = '';
            } else {
                for (var i=0;i<c.length;i++) {
                    app.history.push(c[i]);
                }
                app.input = c[c.length-1].input;
            }
            app.is_mobile = is_mobile();
            // document.getElementById("input").focus();
        }

        init();

</script>
</html>